package demo.hdz.mediacodecdecode.customview;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.SurfaceTexture;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;

import demo.hdz.mediacodecdecode.Logger;
import demo.hdz.mediacodecdecode.Util;
import demo.hdz.mediacodecdecode.filter.BaseFilter;
import demo.hdz.mediacodecdecode.filter.BlackWhiteFilter;
import demo.hdz.mediacodecdecode.filter.NormalFilter;
import demo.hdz.mediacodecdecode.interfaces.IDecodeManager;
import demo.hdz.mediacodecdecode.interfaces.IDecodeOperate;

/**
 * @author hdz
 * @date 2022/05/27 19:24
 */
public class VideoGLSurfaceView extends GLSurfaceView implements IVideoView {
    private static final String TAG = "VideoGLSurfaceView";
    private static int mScreenWidth, mScreenHeight, mVideoWidth, mVideoHeight;
    private SurfaceTexture mSurfaceTexture;
    private IDecodeOperate mDecodeOperate = null;
    private VideoViewUtil mVideoViewUtil;

    private BaseFilter filter;

    public VideoGLSurfaceView(Context context) {
        super(context);
        init();
    }

    public VideoGLSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public static void setSize(int screenWidth, int screenHeight, int videoWidth, int videoHeight) {
        Logger.d(TAG + ",setSize: " + screenWidth + "x" + screenHeight + " " + videoWidth + "x" + videoHeight);
        mScreenWidth = screenWidth;
        mScreenHeight = screenHeight;
        mVideoWidth = videoWidth;
        mVideoHeight = videoHeight;
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            if (mScreenWidth < mScreenHeight) {
                int tmp = mScreenWidth;
                mScreenWidth = mScreenHeight;
                mScreenHeight = tmp;
            }
        } else {
            if (mScreenWidth > mScreenHeight) {
                int tmp = mScreenWidth;
                mScreenWidth = mScreenHeight;
                mScreenHeight = tmp;
            }
        }
        mVideoViewUtil.adjustSize(this, mScreenWidth, mScreenHeight, mVideoWidth, mVideoHeight);
    }

    @Override
    protected void onWindowVisibilityChanged(int visibility) {
        super.onWindowVisibilityChanged(visibility);
        Logger.d(TAG + ",onWindowVisibilityChanged: " + Util.visibility2String(visibility));
    }

    private void init() {
        mVideoViewUtil = new VideoViewUtil();

        setEGLContextClientVersion(2);

        int textureId = createTexture();

        mSurfaceTexture = createSurfaceTexture(textureId);


        filter = new BlackWhiteFilter(getContext(), "shader/v_blackwhite.frag", "shader/f_blackwhite.frag");
        //filter = new NostalgicFilter(getContext(), "shader/v_nostalgic.frag", "shader/f_nostalgic.frag");
        //filter = new SharpenFilter(getContext(), "shader/v_sharpen.frag", "shader/f_sharpen.frag");
        filter = new NormalFilter(getContext(), "shader/v_normal.frag", "shader/f_normal.frag");
        //filter = new DefaultFilter(getContext(), "shader/v_default.frag", "shader/f_default.frag");
        setRenderer(new GLRenderer(mSurfaceTexture, textureId, filter));

        setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    }

    private int createTexture() {
        int[] tex = new int[1];
        //生成一个纹理
        GLES20.glGenTextures(1, tex, 0);

        //将此纹理绑定到外部纹理上
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex[0]);

        //设置纹理过滤参数
        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

        //解除纹理绑定
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);

        return tex[0];
    }

    public SurfaceTexture createSurfaceTexture(int textureId) {
        //根据OES纹理ID实例化SurfaceTexture
        SurfaceTexture mSurfaceTexture = new SurfaceTexture(textureId);
        //当SurfaceTexture接收到一帧数据时，请求OpenGL ES进行渲染
        mSurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
            @Override
            public void onFrameAvailable(SurfaceTexture surfaceTexture) {
                //Logger.e(TAG + ",onFrameAvailable: " + surfaceTexture.getTimestamp());
                // request render
                requestRender();
            }
        });
        return mSurfaceTexture;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Logger.d(TAG + ",onTouchEvent: " + event.toString());
        float x = event.getRawX();
        if (event.getAction() == MotionEvent.ACTION_UP) {
            if (x > mScreenWidth / 2) {
                Logger.d(TAG + ",onTouchEvent: 暂停");
                startOrPause(true);
            } else {
                Logger.d(TAG + ",onTouchEvent: 开始");
                startOrPause(false);
            }
        }
        return true;
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Logger.d(TAG + ",surfaceCreated.");
        super.surfaceCreated(holder);
        mVideoViewUtil.adjustSize(this, mScreenWidth, mScreenHeight, mVideoWidth, mVideoHeight);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        super.surfaceChanged(holder, format, w, h);
        mScreenWidth = w;
        mScreenHeight = h;
        mVideoViewUtil.adjustSize(this, mScreenWidth, mScreenHeight, mVideoWidth, mVideoHeight);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        super.surfaceDestroyed(holder);
        stop();
    }


    @Override
    public boolean isAvailable() {
        return this.mSurfaceTexture != null;
    }

    @Override
    public Surface getSurface() {
        if (mSurfaceTexture != null) {
            return new Surface(mSurfaceTexture);
        }
        return null;
    }

    @Override
    public void setListener(IDecodeOperate o) {
        mDecodeOperate = o;
    }

    @Override
    public void startOrPause(boolean pause) {
        if (mDecodeOperate != null) {
            mDecodeOperate.startOrPause(pause);
        }
    }

    @Override
    public void stop() {
        if (mDecodeOperate != null) {
            mDecodeOperate.stop();
        }
    }

    public void setParameter(String key, int value) {
        if (filter != null) {
            filter.setParameter(key, value);
        }
    }
}
